/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810 *******************************************************************************/ package org.eclipse.ui.internal.registry; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.core.commands.contexts.Context; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker; import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler; import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.contexts.IContextService; import org.eclipse.ui.internal.WorkbenchPlugin; /** * The registry of action set extensions. */ public class ActionSetRegistry implements IExtensionChangeHandler { /** * @since 3.1 */ private class ActionSetPartAssociation { /** * @param partId * @param actionSetId */ public ActionSetPartAssociation(String partId, String actionSetId) { this.partId = partId; this.actionSetId = actionSetId; } String partId; String actionSetId; } private ArrayList children = new ArrayList(); private Map mapPartToActionSetIds = new HashMap(); private Map mapPartToActionSets = new HashMap(); private IContextService contextService; /** * Creates the action set registry. */ public ActionSetRegistry() { contextService = PlatformUI .getWorkbench().getService(IContextService.class); PlatformUI.getWorkbench().getExtensionTracker().registerHandler( this, ExtensionTracker .createExtensionPointFilter(new IExtensionPoint[] { getActionSetExtensionPoint(), getActionSetPartAssociationExtensionPoint() })); readFromRegistry(); } /** * Return the action set part association extension point. * * @return the action set part association extension point * @since 3.1 */ private IExtensionPoint getActionSetPartAssociationExtensionPoint() { return Platform .getExtensionRegistry().getExtensionPoint( PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_ACTION_SET_PART_ASSOCIATIONS); } /** * Return the action set extension point. * * @return the action set extension point * @since 3.1 */ private IExtensionPoint getActionSetExtensionPoint() { return Platform .getExtensionRegistry().getExtensionPoint( PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_ACTION_SETS); } /** * Adds an action set. * @param desc */ private void addActionSet(ActionSetDescriptor desc) { children.add(desc); Context actionSetContext = contextService.getContext(desc.getId()); if (!actionSetContext.isDefined()) { actionSetContext.define(desc.getLabel(), desc.getDescription(), "org.eclipse.ui.contexts.actionSet"); //$NON-NLS-1$ } } /** * Remove the action set. * * @param desc */ private void removeActionSet(IActionSetDescriptor desc) { Context actionSetContext = contextService.getContext(desc.getId()); if (actionSetContext.isDefined()) { actionSetContext.undefine(); } children.remove(desc); } /** * Adds an association between an action set an a part. */ private Object addAssociation(String actionSetId, String partId) { // get the action set ids for this part ArrayList actionSets = (ArrayList) mapPartToActionSetIds.get(partId); if (actionSets == null) { actionSets = new ArrayList(); mapPartToActionSetIds.put(partId, actionSets); } actionSets.add(actionSetId); ActionSetPartAssociation association = new ActionSetPartAssociation(partId, actionSetId); return association; } /** * Finds and returns the registered action set with the given id. * * @param id the action set id * @return the action set, or <code>null</code> if none * @see IActionSetDescriptor#getId */ public IActionSetDescriptor findActionSet(String id) { Iterator i = children.iterator(); while (i.hasNext()) { IActionSetDescriptor desc = (IActionSetDescriptor) i.next(); if (desc.getId().equals(id)) { return desc; } } return null; } /** * Returns a list of the action sets known to the workbench. * * @return a list of action sets */ public IActionSetDescriptor[] getActionSets() { return (IActionSetDescriptor []) children.toArray(new IActionSetDescriptor [children.size()]); } /** * Returns a list of the action sets associated with the given part id. * * @param partId the part id * @return a list of action sets */ public IActionSetDescriptor[] getActionSetsFor(String partId) { // check the resolved map first ArrayList actionSets = (ArrayList) mapPartToActionSets.get(partId); if (actionSets != null) { return (IActionSetDescriptor[]) actionSets .toArray(new IActionSetDescriptor[actionSets.size()]); } // get the action set ids for this part ArrayList actionSetIds = (ArrayList) mapPartToActionSetIds.get(partId); if (actionSetIds == null) { return new IActionSetDescriptor[0]; } // resolve to action sets actionSets = new ArrayList(actionSetIds.size()); for (Iterator i = actionSetIds.iterator(); i.hasNext();) { String actionSetId = (String) i.next(); IActionSetDescriptor actionSet = findActionSet(actionSetId); if (actionSet != null) { actionSets.add(actionSet); } else { WorkbenchPlugin.log("Unable to associate action set with part: " + //$NON-NLS-1$ partId + ". Action set " + actionSetId + " not found."); //$NON-NLS-2$ //$NON-NLS-1$ } } mapPartToActionSets.put(partId, actionSets); return (IActionSetDescriptor[]) actionSets .toArray(new IActionSetDescriptor[actionSets.size()]); } /** * Reads the registry. */ private void readFromRegistry() { for (IExtension extension : getActionSetExtensionPoint().getExtensions()) { addActionSets(PlatformUI.getWorkbench().getExtensionTracker(), extension); } for (IExtension extension : getActionSetPartAssociationExtensionPoint().getExtensions()) { addActionSetPartAssociations(PlatformUI.getWorkbench().getExtensionTracker(), extension); } } @Override public void addExtension(IExtensionTracker tracker, IExtension extension) { String extensionPointUniqueIdentifier = extension.getExtensionPointUniqueIdentifier(); if (extensionPointUniqueIdentifier.equals(getActionSetExtensionPoint().getUniqueIdentifier())) { addActionSets(tracker, extension); } else if (extensionPointUniqueIdentifier.equals(getActionSetPartAssociationExtensionPoint().getUniqueIdentifier())){ addActionSetPartAssociations(tracker, extension); } } /** * @param tracker * @param extension */ private void addActionSetPartAssociations(IExtensionTracker tracker, IExtension extension) { for (IConfigurationElement element : extension.getConfigurationElements()) { if (element.getName().equals(IWorkbenchRegistryConstants.TAG_ACTION_SET_PART_ASSOCIATION)) { String actionSetId = element.getAttribute(IWorkbenchRegistryConstants.ATT_TARGET_ID); for (IConfigurationElement child : element.getChildren()) { if (child.getName().equals(IWorkbenchRegistryConstants.TAG_PART)) { String partId = child.getAttribute(IWorkbenchRegistryConstants.ATT_ID); if (partId != null) { Object trackingObject = addAssociation(actionSetId, partId); if (trackingObject != null) { tracker.registerObject(extension, trackingObject, IExtensionTracker.REF_STRONG); } } } else { WorkbenchPlugin.log("Unable to process element: " + //$NON-NLS-1$ child.getName() + " in action set part associations extension: " + //$NON-NLS-1$ extension.getUniqueIdentifier()); } } } } // TODO: optimize mapPartToActionSets.clear(); } /** * @param tracker * @param extension */ private void addActionSets(IExtensionTracker tracker, IExtension extension) { for (IConfigurationElement element : extension.getConfigurationElements()) { if (element.getName().equals(IWorkbenchRegistryConstants.TAG_ACTION_SET)) { try { ActionSetDescriptor desc = new ActionSetDescriptor(element); addActionSet(desc); tracker.registerObject(extension, desc, IExtensionTracker.REF_WEAK); } catch (CoreException e) { // log an error since its not safe to open a dialog here WorkbenchPlugin .log( "Unable to create action set descriptor.", e.getStatus());//$NON-NLS-1$ } } } // TODO: optimize mapPartToActionSets.clear(); } @Override public void removeExtension(IExtension extension, Object[] objects) { String extensionPointUniqueIdentifier = extension.getExtensionPointUniqueIdentifier(); if (extensionPointUniqueIdentifier.equals(getActionSetExtensionPoint().getUniqueIdentifier())) { removeActionSets(objects); } else if (extensionPointUniqueIdentifier.equals(getActionSetPartAssociationExtensionPoint().getUniqueIdentifier())){ removeActionSetPartAssociations(objects); } } /** * @param objects */ private void removeActionSetPartAssociations(Object[] objects) { for (Object object : objects) { if (object instanceof ActionSetPartAssociation) { ActionSetPartAssociation association = (ActionSetPartAssociation) object; String actionSetId = association.actionSetId; ArrayList actionSets = (ArrayList) mapPartToActionSetIds.get(association.partId); if (actionSets == null) { return; } actionSets.remove(actionSetId); if (actionSets.isEmpty()) { mapPartToActionSetIds.remove(association.partId); } } } // TODO: optimize mapPartToActionSets.clear(); } /** * @param objects */ private void removeActionSets(Object[] objects) { for (Object object : objects) { if (object instanceof IActionSetDescriptor) { IActionSetDescriptor desc = (IActionSetDescriptor) object; removeActionSet(desc); // now clean up the part associations // TODO: this is expensive. We should consider another map from // actionsets // to parts. for (Iterator j = mapPartToActionSetIds.values().iterator(); j .hasNext();) { ArrayList list = (ArrayList) j.next(); list.remove(desc.getId()); if (list.isEmpty()) { j.remove(); } } } } // TODO: optimize mapPartToActionSets.clear(); } }